package cn.buildoncloud.labor.workermanapplet.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * httpClient 工具类
 * Description: com.exampleient.util
 * Created by CuiZibo on 2018/11/23 14:56
 */
@SuppressWarnings("all")
public class HttpUtil {

    private static Logger LOG = LoggerFactory.getLogger(HttpUtil.class);

    private static final int CONNECTION_TIMEOUT = 5000;// 连接超时时间

    private static final int CONNECTION_REQUEST_TIMEOUT = 5000;// 请求超时时间

    private static final int SOCKET_TIMEOUT = 10000;// 数据读取等待超时

//    private static final String HTTP = "http";// http

    private static final String HTTPS = "https";// https

    private static final String DEFAULT_ENCODING = "UTF-8";// 默认编码

    private static final String USERAGENT = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36";

    /**
     * get请求(1.处理http请求;2.处理https请求,信任所有证书)[默认编码:UTF-8]
     *
     * @param url (参数直接拼接到URL后面，即http://test.com?a=1&b=2的形式)
     * @return
     */
    public static String get(String url) {
        return get(url, null, null, CONNECTION_TIMEOUT, DEFAULT_ENCODING);
    }

    /**
     * get请求(1.处理http请求;2.处理https请求,信任所有证书)[默认编码:UTF-8]
     *
     * @param url    (url不带参数，例：http://test.com)
     * @param reqMap (参数放置到一个map中)
     * @return
     */
    public static String get(String url, Map<String, Object> reqMap) {
        return get(url, reqMap, null, CONNECTION_TIMEOUT, DEFAULT_ENCODING);
    }

    /**
     * get请求(1.处理http请求;2.处理https请求,信任所有证书)
     *
     * @param url      (只能是http或https请求)
     * @param encoding
     * @return
     */
    public static String get(String url, Map<String, Object> reqMap, Map<String, String> headers, Integer timeOut, String encoding) {
        String result = "";
        if (StringUtils.isBlank(url)) {
            return result;
        }
        // 处理参数
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        if (reqMap != null && reqMap.keySet().size() > 0) {
            Iterator<Map.Entry<String, Object>> iter = reqMap.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Object> entity = iter.next();
                params.add(new BasicNameValuePair(entity.getKey(), String.valueOf(entity.getValue())));
            }
        }
        //初始化httpClient
        CloseableHttpClient httpClient = null;
        if (url.startsWith(HTTPS)) {
            // 创建一个SSL信任所有证书的httpClient对象
            httpClient = HttpUtil.createSSLInsecureClient();
        } else {
            httpClient = HttpClients.createDefault();
        }

        CloseableHttpResponse response = null;
        HttpGet httpGet = null;

        try {
            //处理参数
            if (params != null && params.size() > 0) {
                URIBuilder builder = new URIBuilder(url);
                builder.setParameters(params);
                httpGet = new HttpGet(builder.build());
            } else {
                httpGet = new HttpGet(url);
            }
            //处理超时时间
            if (timeOut == null)
                timeOut = CONNECTION_TIMEOUT;
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(timeOut)   //设置连接超时时间
                    .setConnectionRequestTimeout(timeOut) // 设置请求超时时间
                    .setSocketTimeout(timeOut)
                    .setRedirectsEnabled(true)//默认允许自动重定向
                    .build();
            httpGet.setConfig(requestConfig);
            //处理header
            httpGet.setHeader("User-Agent", USERAGENT);
            httpGet.setHeader("source","applet");
            if (headers != null) {
                for (Map.Entry<String, String> e : headers.entrySet()) {
                    httpGet.setHeader(e.getKey(), e.getValue());
                }
            }
            // 发送请求，并接收响应
            response = httpClient.execute(httpGet);

            result = handleResponse(encoding, response);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }

        return result;
    }

    /**
     * post请求(1.处理http请求;2.处理https请求,信任所有证书)[默认编码:UTF-8]
     *
     * @param url
     * @param reqMap
     * @return
     */
    public static String post(String url, Map<String, Object> reqMap) {
        return post(url, reqMap, null, CONNECTION_TIMEOUT, DEFAULT_ENCODING);
    }

    /**
     * post请求并设置请求header
     *
     * @param url
     * @param reqMap
     * @param headers
     * @return
     */
    public static String post(String url, Map<String, Object> reqMap, Map<String, String> headers) {
        return post(url, reqMap, headers, CONNECTION_TIMEOUT, DEFAULT_ENCODING);
    }

    /**
     * post请求并设置请求超时时间
     *
     * @param url
     * @param reqMap
     * @param timeOut
     * @return
     */
    public static String post(String url, Map<String, Object> reqMap, int timeOut) {
        return post(url, reqMap, null, timeOut, DEFAULT_ENCODING);
    }

    /**
     * post请求并设置header和超时时间
     *
     * @param url
     * @param reqMap
     * @param headers
     * @param timeOut
     * @return
     */
    public static String post(String url, Map<String, Object> reqMap, Map<String, String> headers, int timeOut) {
        return post(url, reqMap, headers, timeOut, DEFAULT_ENCODING);
    }

    /**
     * post请求(1.处理http请求;2.处理https请求,信任所有证书)
     *
     * @param url
     * @param reqMap   入参是个map
     * @param encoding
     * @return
     */
    public static String post(String url, Map<String, Object> reqMap, Map<String, String> headers, Integer timeOut, String encoding) {
        String result = "";
        if (StringUtils.isBlank(url)) {
            return result;
        }
        // 添加参数
        List<NameValuePair> params = new ArrayList<>();
        if (reqMap != null && reqMap.keySet().size() > 0) {
            Iterator<Map.Entry<String, Object>> iter = reqMap.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Object> entity = iter.next();
                params.add(new BasicNameValuePair(entity.getKey(), String.valueOf(entity.getValue())));
            }
        }
        //初始化httpClient
        CloseableHttpClient httpClient = null;
        if (url.startsWith(HTTPS)) {
            // 创建一个SSL信任所有证书的httpClient对象
            httpClient = HttpUtil.createSSLInsecureClient();
        } else {
            httpClient = HttpClients.createDefault();
        }
        CloseableHttpResponse response = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            //处理超时时间
            if (timeOut == null)
                timeOut = CONNECTION_TIMEOUT;
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(timeOut)   //设置连接超时时间
                    .setConnectionRequestTimeout(timeOut) // 设置请求超时时间
                    .setSocketTimeout(timeOut)
                    .setRedirectsEnabled(true)//默认允许自动重定向
                    .build();
            httpPost.setConfig(requestConfig);
            //处理header
            httpPost.setHeader("User-Agent", USERAGENT);
            httpPost.setHeader("source","applet");
            if (headers != null) {
                for (Map.Entry<String, String> e : headers.entrySet()) {
                    httpPost.setHeader(e.getKey(), e.getValue());
                }
            }
            //处理参数
            httpPost.setEntity(new UrlEncodedFormEntity(params, encoding));
            // 发送请求，并接收响应
            response = httpClient.execute(httpPost);
            result = handleResponse(encoding, response);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }

        return result;
    }

    /**
     * post请求(1.处理http请求;2.处理https请求,信任所有证书)
     *
     * @param url
     * @param jsonParams 入参是个json字符串
     * @param encoding
     * @return
     */
    public static String post(String url, String jsonParams, Map<String, String> headers, Integer timeOut) {
        String result = "";
        if (StringUtils.isBlank(url)) {
            return result;
        }
        //初始化httpClient
        CloseableHttpClient httpClient = null;
        if (url.startsWith(HTTPS)) {
            // 创建一个SSL信任所有证书的httpClient对象
            httpClient = HttpUtil.createSSLInsecureClient();
        } else {
            httpClient = HttpClients.createDefault();
        }
        CloseableHttpResponse response = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            //处理超时时间
            if (timeOut == null)
                timeOut = CONNECTION_TIMEOUT;
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(timeOut)   //设置连接超时时间
                    .setConnectionRequestTimeout(timeOut) // 设置请求超时时间
                    .setSocketTimeout(timeOut)
                    .setRedirectsEnabled(true)//默认允许自动重定向
                    .build();
            httpPost.setConfig(requestConfig);
            //处理header
            httpPost.setHeader("User-Agent", USERAGENT);
            httpPost.setHeader("source","applet");
            if (headers != null) {
                for (Map.Entry<String, String> e : headers.entrySet()) {
                    httpPost.setHeader(e.getKey(), e.getValue());
                }
            }
            //处理参数
            httpPost.setEntity(new StringEntity(jsonParams, ContentType.create("application/json", DEFAULT_ENCODING)));
            // 发送请求，并接收响应
            response = httpClient.execute(httpPost);
            result = handleResponse(DEFAULT_ENCODING, response);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeResource(httpClient, response);
        }
        return result;
    }

    /**
     * post方式传输文件，可以带其他参数和超时时间
     * 未添加自定义header
     * @param url 请求url
     * @param multipartFiles 文件集合
     * @param fileParName 接收文件的参数
     * @param params 参数
     * @param timeout 超时时间
     * @return
     */
    public static String postFile(String url,
                                  List<MultipartFile> multipartFiles,
                                  String fileParName,
                                  Map<String, Object> params,
                                  int timeOut) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = null;
        CloseableHttpResponse response = null;
        MultipartEntityBuilder builder = null;
        HttpEntity entity = null;
        String result = "";
        try {
            httpPost = new HttpPost(url);

            builder = MultipartEntityBuilder.create();
            builder.setCharset(java.nio.charset.Charset.forName(DEFAULT_ENCODING));
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

            String fileName = null;
            MultipartFile multipartFile = null;
            for (int i = 0; i < multipartFiles.size(); i++) {
                multipartFile = multipartFiles.get(i);
                fileName = multipartFile.getOriginalFilename();
                builder.addBinaryBody(fileParName, multipartFile.getInputStream(), ContentType.MULTIPART_FORM_DATA, fileName);// 文件流
            }
            //决中文乱码
            if (params != null) {
                ContentType contentType = ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), Consts.UTF_8);
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    if (entry.getValue() == null)
                        continue;
                    // 类似浏览器表单提交，对应input的name和value
                    builder.addTextBody(entry.getKey(), entry.getValue().toString(), contentType);
                }
            }
            entity = builder.build();
            httpPost.setEntity(entity);
            httpPost.setHeader("source","applet");
            // 设置连接超时时间
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(timeOut)   //设置连接超时时间
                    .setConnectionRequestTimeout(timeOut) // 设置请求超时时间
                    .setSocketTimeout(timeOut)
                    .setRedirectsEnabled(true)//默认允许自动重定向
                    .build();
            httpPost.setConfig(requestConfig);
            response = httpClient.execute(httpPost);// 执行提交
            result = handleResponse(DEFAULT_ENCODING, response);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 创建一个SSL信任所有证书的httpClient对象
     *
     * @return
     */
    public static CloseableHttpClient createSSLInsecureClient() {
        try {
            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
                // 默认信任所有证书
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(sslContext);

            return HttpClients.custom().setSSLSocketFactory(sslcsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }

        return HttpClients.createDefault();
    }

    /**
     * 在调用SSL之前需要重写验证方法，取消检测SSL
     * 创建ConnectionManager，添加Connection配置信息
     *
     * @return HttpClient 支持https
     */
    private static HttpClient sslClient() {
        try {
            // 在调用SSL之前需要重写验证方法，取消检测SSL
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String str) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String str) {
                }
            };
            SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            ctx.init(null, new TrustManager[]{trustManager}, null);
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            // 创建Registry
            RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT)
                    .setExpectContinueEnabled(Boolean.TRUE).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
                    .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", socketFactory).build();
            // 创建ConnectionManager，添加Connection配置信息
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
                    .setDefaultRequestConfig(requestConfig).build();
            return closeableHttpClient;
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 处理响应，获取响应报文
     *
     * @param url
     * @param encoding
     * @param response
     * @return
     * @throws IOException
     */
    private static String handleResponse(String encoding, CloseableHttpResponse response) {
        StringBuilder sb = new StringBuilder();
        BufferedReader br = null;

        try {
            if (response != null) {
//                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    // 获取响应实体
                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                        br = new BufferedReader(new InputStreamReader(entity.getContent(), encoding));
                        String s = null;
                        while ((s = br.readLine()) != null) {
                            sb.append(s);
                        }
                    }

                    // 释放entity
                    EntityUtils.consume(entity);
//                } else if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
//                    LOG.error("HttpStatus 404", response.getEntity());
//                } else if (response.getStatusLine().getStatusCode() == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
//                    LOG.error("HttpStatus 500", response.getEntity());
//                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();
    }

    /**
     * 释放资源
     *
     * @param httpClient
     * @param response
     */
    private static void closeResource(CloseableHttpClient httpClient, CloseableHttpResponse response) {
        if (response != null) {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (httpClient != null) {
            try {
                httpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
